using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using OpenTK.Graphics.OpenGL;
using OpenTK;
using SM64DSe;
using System.IO;

namespace MKDS_Course_Editor
{
    public partial class bmd_view : Form
    {
        string file_ = "";
        bool col = false;
        public bmd_view(string file)
        {
            InitializeComponent();
            file_ = file;
            glLevelView.MouseWheel += glLevelView_MouseWheel;
            m_MouseDown = MouseButtons.None;
            m_Hovered = 0xFFFFFFFF;
            m_LastHovered = 0xFFFFFFFF;
            m_Selected = 0xFFFFFFFF;
            m_LastSelected = 0xFFFFFFFF;
            m_LastClicked = 0xFFFFFFFF;
            m_ObjectBeingPlaced = 0xFFFF;
            m_ShiftPressed = false;

        }


        private void bmd_view_Load(object sender, EventArgs e)
        {
            if (File.Exists(file_.Replace(".bmd", ".kcl").Replace("_all", "")))
            {
                m_LevelCollMap = new SM64DSe.KCL(new NitroFile(file_.Replace(".bmd", ".kcl").Replace("_all", "")));
                col = true;
            }
        }
        private void UpdateCamera()
        {
            Vector3 up;

            if (Math.Cos(m_CamRotation.Y) < 0)
            {
                m_UpsideDown = true;
                up = new Vector3(0.0f, -1.0f, 0.0f);
            }
            else
            {
                m_UpsideDown = false;
                up = new Vector3(0.0f, 1.0f, 0.0f);
            }

            m_CamPosition.X = m_CamDistance * (float)Math.Cos(m_CamRotation.X) * (float)Math.Cos(m_CamRotation.Y);
            m_CamPosition.Y = m_CamDistance * (float)Math.Sin(m_CamRotation.Y);
            m_CamPosition.Z = m_CamDistance * (float)Math.Sin(m_CamRotation.X) * (float)Math.Cos(m_CamRotation.Y);

            Vector3 skybox_target;
            skybox_target.X = -(float)Math.Cos(m_CamRotation.X) * (float)Math.Cos(m_CamRotation.Y);
            skybox_target.Y = -(float)Math.Sin(m_CamRotation.Y);
            skybox_target.Z = -(float)Math.Sin(m_CamRotation.X) * (float)Math.Cos(m_CamRotation.Y);

            Vector3.Add(ref m_CamPosition, ref m_CamTarget, out m_CamPosition);

            m_CamMatrix = Matrix4.LookAt(m_CamPosition, m_CamTarget, up);
            m_SkyboxMatrix = Matrix4.LookAt(Vector3.Zero, skybox_target, up);
        }
        //private bool m_LevelModified;

        // level data
        
        public int m_NumAreas;

        private bool m_GLLoaded;

        private Vector2 m_CamRotation;
        private Vector3 m_CamTarget;
        private float m_CamDistance;
        private float m_AspectRatio;
        private float m_PixelFactorX, m_PixelFactorY;
        private Vector3 m_CamPosition;
        private bool m_UpsideDown;
        private Matrix4 m_CamMatrix, m_SkyboxMatrix;

        private uint[] m_PickingFrameBuffer;

        //private int m_BBShader;
        //private int m_BBShaderCamPos;

        private bool m_ShowCommonLayer;
        private int m_AuxLayerNum;
        private int m_EditMode;

        private MouseButtons m_MouseDown;
        private Point m_LastMouseClick, m_LastMouseMove;
        private Point m_MouseCoords;

        private uint m_Hovered, m_LastHovered;
        private uint m_Selected, m_LastSelected;
        private uint m_LastClicked;
        private uint m_ObjectBeingPlaced;
        private bool m_ShiftPressed;

        private BMD m_SkyboxModel;
        private BMD m_LevelModel;
        private SM64DSe.KCL m_LevelCollMap;

        private int m_SkyboxDL;
        private int[,] m_LevelModelDLs;
        private int[,] m_ObjectDLs;
        private int m_SelectHiliteDL;
        private int m_HoverHiliteDL;


        private void glLevelView_Load(object sender, EventArgs e)
        {
            // initialize OpenGL
            glLevelView.Context.MakeCurrent(glLevelView.WindowInfo);

            m_PickingFrameBuffer = new uint[9];

            GL.Viewport(glLevelView.ClientRectangle);

            m_AspectRatio = (float)glLevelView.Width / (float)glLevelView.Height;
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadIdentity();
            Matrix4 projmtx = Matrix4.CreatePerspectiveFieldOfView((float)((70.0f * Math.PI) / 180.0f), m_AspectRatio, 0.01f, 1000.0f);
            GL.MultMatrix(ref projmtx);

            GL.Enable(EnableCap.DepthTest);
            GL.ClearDepth(1f);

            // lighting!
            //GL.Light(LightName.Light0, LightParameter.Position, new Vector4(0.0f, -0.646484375f, -0.646484375f, 0.0f));
            GL.Light(LightName.Light0, LightParameter.Position, new Vector4(1.0f, 1.0f, 1.0f, 0.0f));
            GL.Light(LightName.Light0, LightParameter.Ambient, Color.SkyBlue);
            GL.Light(LightName.Light0, LightParameter.Diffuse, Color.SkyBlue);
            GL.Light(LightName.Light0, LightParameter.Specular, Color.SkyBlue);
            /*GL.Light(LightName.Light1, LightParameter.Position, new Vector4(-0.666015625f, -0.35546875f, -0.1103515625f, 0.0f));
            GL.Light(LightName.Light1, LightParameter.Ambient, Color.Red);
            GL.Light(LightName.Light1, LightParameter.Diffuse, Color.Red);
            GL.Light(LightName.Light1, LightParameter.Specular, Color.Red);*/

            GL.Enable(EnableCap.Normalize);

            m_CamRotation = new Vector2(1.5f, (float)Math.PI / 8.0f);
            //m_CamRotation = new Vector2(0.0f, 0.0f);
            m_CamTarget = new Vector3(0.0f, 0.0f, 0.0f);
            m_CamDistance = 6.5f;
            UpdateCamera();

            m_PixelFactorX = ((2.0f * (float)Math.Tan((35.0f * Math.PI) / 180.0f) * m_AspectRatio) / (float)(glLevelView.Width));
            m_PixelFactorY = ((2.0f * (float)Math.Tan((35.0f * Math.PI) / 180.0f)) / (float)(glLevelView.Height));

            GL.Enable(EnableCap.Blend);
            GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);

            GL.Enable(EnableCap.AlphaTest);
            GL.AlphaFunc(AlphaFunction.Greater, 0.0f);

            GL.Enable(EnableCap.Texture2D);

            GL.Disable(EnableCap.CullFace);
            //GL.CullFace(CullFaceMode.Back);


            m_LevelModel = new SM64DSe.BMD(new SM64DSe.NitroFile(file_));
            //PopulateObjectList();

            // prerender the skybox
            //UpdateSkybox(-1);

            // prerender the level model
            m_LevelModel.PrepareToRender();
            int nlchunks = m_LevelModel.m_ModelChunks.Length;
            m_LevelModelDLs = new int[nlchunks, 3];

            for (int c = 0; c < nlchunks; c++)
            {
                m_LevelModelDLs[c, 0] = GL.GenLists(1);
                GL.NewList(m_LevelModelDLs[c, 0], ListMode.Compile);
                m_LevelModel.m_ModelChunks[c].Render(SM64DSe.BMD.RenderMode.Opaque, 1.0f);
                GL.EndList();

                m_LevelModelDLs[c, 1] = GL.GenLists(1);
                GL.NewList(m_LevelModelDLs[c, 1], ListMode.Compile);
                m_LevelModel.m_ModelChunks[c].Render(SM64DSe.BMD.RenderMode.Translucent, 1.0f);
                GL.EndList();

                m_LevelModelDLs[c, 2] = GL.GenLists(1);
                GL.NewList(m_LevelModelDLs[c, 2], ListMode.Compile);
                m_LevelModel.m_ModelChunks[c].Render(SM64DSe.BMD.RenderMode.Picking, 1.0f);
                GL.EndList();
            }

            // prerender the objects
            m_ObjectDLs = new int[8, 3];
            for (int l = 0; l < 8; l++)
            {
                //RenderObjectLists(RenderMode.Opaque, l);
                //RenderObjectLists(RenderMode.Translucent, l);
                //RenderObjectLists(RenderMode.Picking, l);
            }

            m_SelectHiliteDL = GL.GenLists(1);
            m_HoverHiliteDL = GL.GenLists(1);

            m_GLLoaded = true;
        }

        private void glLevelView_Resize(object sender, EventArgs e)
        {
            if (!m_GLLoaded) return;
            glLevelView.Context.MakeCurrent(glLevelView.WindowInfo);

            GL.Viewport(glLevelView.ClientRectangle);

            m_AspectRatio = (float)glLevelView.Width / (float)glLevelView.Height;
            GL.MatrixMode(MatrixMode.Projection);
            Matrix4 projmtx = Matrix4.CreatePerspectiveFieldOfView((float)(70.0f * Math.PI / 180.0f), m_AspectRatio, 0.01f, 1000.0f);
            GL.LoadMatrix(ref projmtx);

            m_PixelFactorX = ((2.0f * (float)Math.Tan((35.0f * Math.PI) / 180.0f) * m_AspectRatio) / (float)(glLevelView.Width));
            m_PixelFactorY = ((2.0f * (float)Math.Tan((35.0f * Math.PI) / 180.0f)) / (float)(glLevelView.Height));
        }

        private void glLevelView_Paint(object sender, PaintEventArgs e)
        {
            if (!m_GLLoaded) return;
            glLevelView.Context.MakeCurrent(glLevelView.WindowInfo);

            // Pass 1 - picking mode rendering (render stuff with fake colors that identify objects)

            GL.ClearColor(1.0f, 1.0f, 1.0f, 1.0f);
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit);

            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadMatrix(ref m_CamMatrix);

            GL.Disable(EnableCap.AlphaTest);
            GL.Disable(EnableCap.Blend);
            GL.Disable(EnableCap.Dither);
            GL.Disable(EnableCap.LineSmooth);
            GL.Disable(EnableCap.PolygonSmooth);
            GL.BindTexture(TextureTarget.Texture2D, 0);
            GL.Disable(EnableCap.Lighting);

            for (int a = 0; a < m_LevelModelDLs.GetLength(0); a++)
            {
                GL.Color4(Color.FromArgb(a));
                GL.CallList(m_LevelModelDLs[a, 2]);
            }

            if (m_ShowCommonLayer) GL.CallList(m_ObjectDLs[0, 2]);
            if (m_AuxLayerNum > 0) GL.CallList(m_ObjectDLs[m_AuxLayerNum, 2]);

            GL.Flush();
            GL.ReadPixels(m_MouseCoords.X - 1, glLevelView.Height - m_MouseCoords.Y + 1, 3, 3, PixelFormat.Bgra, PixelType.UnsignedByte, m_PickingFrameBuffer);

            // Pass 2 - real rendering

            GL.DepthMask(true);
            GL.ClearColor(0.0f, 0.0f, 0.125f, 1.0f);
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit);

            GL.Enable(EnableCap.AlphaTest);
            GL.Enable(EnableCap.Blend);
            GL.Enable(EnableCap.Dither);
            GL.Enable(EnableCap.LineSmooth);
            GL.Enable(EnableCap.PolygonSmooth);

            GL.LoadMatrix(ref m_SkyboxMatrix);
            GL.CallList(m_SkyboxDL);

            GL.LoadMatrix(ref m_CamMatrix);

            // opaque polygons
            for (int a = 0; a < m_LevelModelDLs.GetLength(0); a++)
                GL.CallList(m_LevelModelDLs[a, 0]);

            if (m_ShowCommonLayer) GL.CallList(m_ObjectDLs[0, 0]);
            if (m_AuxLayerNum > 0) GL.CallList(m_ObjectDLs[m_AuxLayerNum, 0]);

            // translucent polygons
            for (int a = 0; a < m_LevelModelDLs.GetLength(0); a++)
                GL.CallList(m_LevelModelDLs[a, 1]);

            if (m_ShowCommonLayer) GL.CallList(m_ObjectDLs[0, 1]);
            if (m_AuxLayerNum > 0) GL.CallList(m_ObjectDLs[m_AuxLayerNum, 1]);

            // highlight outlines
            //if (m_SelectedObject != null && m_SelectedObject != m_HoveredObject) GL.CallList(m_SelectHiliteDL);
            //if (m_HoveredObject != null) GL.CallList(m_HoverHiliteDL);

            // axes (temp)
            /*GL.BindTexture(TextureTarget.Texture2D, 0);
            GL.LineWidth(2.0f);
            GL.Begin(BeginMode.Lines);
            GL.Color3(1f, 0f, 0f);
            GL.Vertex3(0f, 0f, 0f);
            GL.Vertex3(500f, 0f, 0f);
            GL.Color3(0f, 1f, 0f);
            GL.Vertex3(0f, 0f, 0f);
            GL.Vertex3(0f, 500f, 0f);
            GL.Color3(0f, 0f, 1f);
            GL.Vertex3(0f, 0f, 0f);
            GL.Vertex3(0f, 0f, 500f);
            GL.End();*/

            // enable this to view the level's collision map (slow)
            /*if (col)
            {
                int n = 0;
                foreach (KCL.Plane plane in m_LevelCollMap.m_Planes)
                {
                    Color[] colors = { Color.Red, Color.Green, Color.Blue, Color.Cyan, Color.Magenta, Color.Yellow, Color.White, Color.OrangeRed };
                    GL.Color3(colors[n & 7]);
                    //GL.Color3(colors[(n >> 12) & 7]);
                    n++;
                    if (n != 37) continue;

                    GL.Begin(BeginMode.Triangles);
                    Vector3 lol1 = Vector3.Cross(plane.m_Dir1, plane.m_Normal);
                    float lol1len = plane.m_Length / (float)Math.Cos(Math.Acos(Math.Min(1f, Vector3.Dot(lol1, plane.m_Dir3))));
                    GL.Vertex3(Vector3.Add(plane.m_Position, Vector3.Multiply(lol1, lol1len)));

                    GL.Vertex3(plane.m_Position);

                    Vector3 lol2 = Vector3.Cross(plane.m_Normal, plane.m_Dir2);
                    float lol2len = plane.m_Length / (float)Math.Cos(Math.Acos(Math.Min(1f, Vector3.Dot(lol2, plane.m_Dir3))));
                    //GL.Vertex3(plane.m_Position);
                    GL.Vertex3(Vector3.Add(plane.m_Position, Vector3.Multiply(lol2, lol2len)));

                    GL.End();
                }
            }*/
            // enable this to view the octree cubes (slow as well)
            /*GL.BindTexture(TextureTarget.Texture2D, 0);
            GL.LineWidth(2f);
            foreach (KCL.OctreeNode node in KCL.OctreeNode.m_List)
            {
                Vector3 s0 = node.m_Pos;
                Vector3 s1 = node.m_Pos + node.m_Size;

                //if (node.m_LOL)
                //    GL.Color3(Color.LimeGreen);
               // else
                if (node.m_NumPlanes > 10)
                    GL.Color3(Color.Red);
                else if (node.m_NumPlanes > 8)
                    GL.Color3(Color.Fuchsia);
                //else if (node.m_NumPlanes == 8)
                 //   GL.Color3(Color.Blue);
                else
                    continue;
                    //GL.Color3(Color.Green);

                GL.Begin(BeginMode.LineStrip);
                GL.Vertex3(s1.X, s1.Y, s1.Z);
                GL.Vertex3(s0.X, s1.Y, s1.Z);
                GL.Vertex3(s0.X, s1.Y, s0.Z);
                GL.Vertex3(s1.X, s1.Y, s0.Z);
                GL.Vertex3(s1.X, s1.Y, s1.Z);
                GL.Vertex3(s1.X, s0.Y, s1.Z);
                GL.Vertex3(s0.X, s0.Y, s1.Z);
                GL.Vertex3(s0.X, s0.Y, s0.Z);
                GL.Vertex3(s1.X, s0.Y, s0.Z);
                GL.Vertex3(s1.X, s0.Y, s1.Z);
                GL.End();

                GL.Begin(BeginMode.Lines);
                GL.Vertex3(s0.X, s1.Y, s1.Z);
                GL.Vertex3(s0.X, s0.Y, s1.Z);
                GL.Vertex3(s0.X, s1.Y, s0.Z);
                GL.Vertex3(s0.X, s0.Y, s0.Z);
                GL.Vertex3(s1.X, s1.Y, s0.Z);
                GL.Vertex3(s1.X, s0.Y, s0.Z);
                GL.End();
            }*/


            glLevelView.SwapBuffers();
        }

        private void glLevelView_MouseDown(object sender, MouseEventArgs e)
        {
            if (m_MouseDown != MouseButtons.None) return;

            if (m_ObjectBeingPlaced != 0xFFFF)
            {
                int type = (int)(m_ObjectBeingPlaced >> 16);
                ushort id = (ushort)(m_ObjectBeingPlaced & 0xFFFF);
                //if (type == 0 && IsSimpleObject(id))
                //    type = 5;

               //LevelObject obj = AddObject(type, id, 0, 0);
              // obj.Position = Get3DCoords(e.Location, 2f);
             //   obj.GenerateProperties();
              //  pgObjectProperties.SelectedObject = obj.m_Properties;

             //   m_Selected = obj.m_UniqueID;
             //   m_SelectedObject = obj;
             //   m_LastSelected = obj.m_UniqueID;
              //  m_Hovered = obj.m_UniqueID;
              //  m_HoveredObject = obj;
              //  m_LastHovered = obj.m_UniqueID;
             //   m_LastClicked = obj.m_UniqueID;

               // RefreshObjects(m_SelectedObject.m_Layer);

                if (!m_ShiftPressed)
                {
                    m_ObjectBeingPlaced = 0xFFFF;
                  //  slStatusLabel.Text = "Object added.";
                }
            }
            else if ((m_PickingFrameBuffer[4] == m_PickingFrameBuffer[1]) &&
                (m_PickingFrameBuffer[4] == m_PickingFrameBuffer[3]) &&
                (m_PickingFrameBuffer[4] == m_PickingFrameBuffer[5]) &&
                (m_PickingFrameBuffer[4] == m_PickingFrameBuffer[7]))
            {
                /*if (btnRemoveSel.Checked)
                {
                    uint sel = m_PickingFrameBuffer[4];
                    uint type = (sel >> 28);
                    if (type == m_EditMode)
                    {
                        LevelObject obj = m_LevelObjects[sel];
                        RemoveObject(obj);
                        RefreshObjects(obj.m_Layer);

                        if (!m_ShiftPressed)
                        {
                            btnRemoveSel.Checked = false;
                            slStatusLabel.Text = "Object removed.";
                        }
                    }
                }
                else
                    m_LastClicked = m_PickingFrameBuffer[4];
               */ 
            }

            m_MouseDown = e.Button;
            m_LastMouseClick = e.Location;
            m_LastMouseMove = e.Location;
        }
        public static float X = 0.0f;
        public static float Y = 0.0f;
        public static float ang = 0.0f;
        public static float dist = 0.0f;//2.5
        public static float elev = 0.0f;
        public bool wire = false;
        public int fix = 0;
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            switch (keyData)
            {
                case Keys.Right:
                    ang -= 0.1f;
                    m_CamRotation.X = ang;
                    UpdateCamera();
                    glLevelView.Refresh();
                    return true;
                case Keys.Left:
                    ang += 0.1f;
                    m_CamRotation.X = ang;
                    UpdateCamera();
                    glLevelView.Refresh();
                    return true;
                case Keys.Up:
                    elev += 0.1f;
                    m_CamRotation.Y = elev;
                    UpdateCamera();
                    glLevelView.Refresh();
                    return true;
                case Keys.Down:
                    elev -= 0.1f;
                    m_CamRotation.Y = elev;
                    UpdateCamera();
                    glLevelView.Refresh();
                    return true;
                case Keys.Z:
                    X -= 0.1f;
                    m_CamPosition.X = X;
                    UpdateCamera();
                    glLevelView.Refresh();
                    return true;
                case Keys.X:
                    X += 0.1f;
                    m_CamPosition.X = X;
                    UpdateCamera();
                    glLevelView.Refresh();
                    return true;
                case Keys.A:
                    Y -= 0.1f;
                    m_CamPosition.Y = Y;
                    UpdateCamera();
                    glLevelView.Refresh();
                    return true;
                case Keys.S:
                    Y += 0.1f;
                    m_CamPosition.Y = Y;
                    UpdateCamera();
                    glLevelView.Refresh();
                    return true;
                case Keys.W:
                    if (wire == false)
                    {
                        OpenTK.Graphics.OpenGL.GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
                        glLevelView.Refresh();
                        wire = true;
                    }
                    else
                    {
                        OpenTK.Graphics.OpenGL.GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
                        glLevelView.Refresh();
                        wire = false;
                    }
                    return true;
                case Keys.Escape:
                    X = 0.0f;
                    Y = 0.0f;
                    ang = 0.0f;
                    dist = 0.0f;
                    elev = 0.0f;
                    OpenTK.Graphics.OpenGL.GL.Rotate(ang, 0, 1, 0);
                    OpenTK.Graphics.OpenGL.GL.Rotate(elev, 1, 0, 0);
                    OpenTK.Graphics.OpenGL.GL.Translate(X, Y, -dist);
                    glLevelView.Refresh();
                    return true;
                default:
                    return base.ProcessCmdKey(ref msg, keyData);
            }
        }
        private void glLevelView_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button != m_MouseDown) return;

            if ((Math.Abs(e.X - m_LastMouseClick.X) < 3) && (Math.Abs(e.Y - m_LastMouseClick.Y) < 3) &&
                (m_PickingFrameBuffer[4] == m_PickingFrameBuffer[1]) &&
                (m_PickingFrameBuffer[4] == m_PickingFrameBuffer[3]) &&
                (m_PickingFrameBuffer[4] == m_PickingFrameBuffer[5]) &&
                (m_PickingFrameBuffer[4] == m_PickingFrameBuffer[7]))
            {
                uint sel = m_PickingFrameBuffer[4];
                uint type = (sel >> 28);
                if (type == m_EditMode)
                {
                    m_Selected = sel;
                    if ((type == 0) || (type == 5))
                        return;

                    if (m_LastSelected != m_Selected)
                    {
                       // LevelObject obj = m_LevelObjects[sel];
                        //RenderObjectHilite(obj, k_SelectionColor, m_SelectHiliteDL);
                        //m_LastSelected = m_Selected;
                        //m_SelectedObject = obj;

                        //pgObjectProperties.SelectedObject = obj.m_Properties;
                        //tvObjectList.SelectedNode = tvObjectList.Nodes.Find(obj.m_UniqueID.ToString("X8"), true)[0];
                    }
                }
                else
                {
                    m_Selected = 0xFFFFFFFF;
                    m_LastSelected = 0xFFFFFFFF;
                    //m_SelectedObject = null;

                    //pgObjectProperties.SelectedObject = null;
                    //tvObjectList.SelectedNode = null;
                }
            }

            m_MouseDown = MouseButtons.None;
        }

        private void glLevelView_MouseMove(object sender, MouseEventArgs e)
        {
            float xdelta = (float)(e.X - m_LastMouseMove.X);
            float ydelta = (float)(e.Y - m_LastMouseMove.Y);

            m_MouseCoords = e.Location;
            m_LastMouseMove = e.Location;

            if (m_MouseDown != MouseButtons.None)
            {
                if (m_LastSelected == 0xFFFFFFFF || m_LastSelected != m_LastClicked)
                {
                    if (m_MouseDown == MouseButtons.Right)
                    {
                        /*if (btnReverseRot.Checked)
                        {
                            xdelta = -xdelta;
                            ydelta = -ydelta;
                        }*/

                        if (m_UpsideDown)
                            xdelta = -xdelta;

                        m_CamRotation.X -= xdelta * 0.002f;
                        m_CamRotation.Y -= ydelta * 0.002f;

                        ClampRotation(ref m_CamRotation.X, (float)Math.PI * 2.0f);
                        ClampRotation(ref m_CamRotation.Y, (float)Math.PI * 2.0f);
                    }
                    else if (m_MouseDown == MouseButtons.Left)
                    {
                        xdelta *= 0.005f;
                        ydelta *= 0.005f;

                        m_CamTarget.X -= xdelta * (float)Math.Sin(m_CamRotation.X);
                        m_CamTarget.X -= ydelta * (float)Math.Cos(m_CamRotation.X) * (float)Math.Sin(m_CamRotation.Y);
                        m_CamTarget.Y += ydelta * (float)Math.Cos(m_CamRotation.Y);
                        m_CamTarget.Z += xdelta * (float)Math.Cos(m_CamRotation.X);
                        m_CamTarget.Z -= ydelta * (float)Math.Sin(m_CamRotation.X) * (float)Math.Sin(m_CamRotation.Y);
                    }

                    UpdateCamera();
                }
                else
                {
                    if (m_MouseDown == MouseButtons.Right)
                    {
                        if (m_UpsideDown)
                            xdelta = -xdelta;

                        // TODO take obj/camera rotation into account?
                        //if (m_SelectedObject.SupportsRotation())
                        //{
                        //   m_SelectedObject.YRotation += xdelta * 0.5f;
                        //
                         //   if (m_SelectedObject.YRotation >= 180f)
                        //    {
                        //        m_SelectedObject.YRotation = (float)(-360f + m_SelectedObject.YRotation);
                        //    }
                        //    else if (m_SelectedObject.YRotation < -180f)
                         //   {
                        //        m_SelectedObject.YRotation = (float)(360f + m_SelectedObject.YRotation);
                         //   }
                        //}
                    }
                    else if (m_MouseDown == MouseButtons.Left)
                    {
                        Vector3 between;
                        Vector3 t = new Vector3(0, 0, 0);
                        Vector3.Subtract(ref m_CamPosition, ref t, out between);

                        float objz = (((between.X * (float)Math.Cos(m_CamRotation.X)) + (between.Z * (float)Math.Sin(m_CamRotation.X))) * (float)Math.Cos(m_CamRotation.Y)) + (between.Y * (float)Math.Sin(m_CamRotation.Y));

                        xdelta *= m_PixelFactorX * objz;
                        ydelta *= -m_PixelFactorY * objz;

                        float _xdelta = (xdelta * (float)Math.Sin(m_CamRotation.X)) - (ydelta * (float)Math.Sin(m_CamRotation.Y) * (float)Math.Cos(m_CamRotation.X));
                        float _ydelta = ydelta * (float)Math.Cos(m_CamRotation.Y);
                        float _zdelta = (xdelta * (float)Math.Cos(m_CamRotation.X)) + (ydelta * (float)Math.Sin(m_CamRotation.Y) * (float)Math.Sin(m_CamRotation.X));

                        //m_SelectedObject.Position.X += _xdelta;
                        //m_SelectedObject.Position.Y += _ydelta;
                        //m_SelectedObject.Position.Z -= _zdelta;
                    }

                    //UpdateSelection();
                }
            }
            //else
            {
                if ((m_PickingFrameBuffer[4] == m_PickingFrameBuffer[1]) &&
                    (m_PickingFrameBuffer[4] == m_PickingFrameBuffer[3]) &&
                    (m_PickingFrameBuffer[4] == m_PickingFrameBuffer[5]) &&
                    (m_PickingFrameBuffer[4] == m_PickingFrameBuffer[7]))
                {
                    uint sel = m_PickingFrameBuffer[4];
                    uint type = (sel >> 28);
                    if (type == m_EditMode)
                    {
                        m_Hovered = sel;
                        if ((type == 0) || (type == 5))
                        {
                            m_LastHovered = 0xFFFFFFFF;
                            //m_HoveredObject = null;
                        }
                        else
                            if (m_LastHovered != m_Hovered)
                            {
                                //LevelObject obj = m_LevelObjects[sel];
                                //RenderObjectHilite(obj, k_HoverColor, m_HoverHiliteDL);
                              //  m_LastHovered = m_Hovered;
                              //  m_HoveredObject = obj;
                            }
                    }
                    else
                    {
                        m_Hovered = 0xFFFFFFFF;
                        m_LastHovered = 0xFFFFFFFF;
                        //m_HoveredObject = null;
                    }
                }
            }

            glLevelView.Refresh();
        }
        private void ClampRotation(ref float val, float twopi)
        {
            if (val > twopi)
            {
                while (val > twopi)
                    val -= twopi;
            }
            else if (val < -twopi)
            {
                while (val < -twopi)
                    val += twopi;
            }
        }

        private void glLevelView_MouseWheel(object sender, MouseEventArgs e)
        {
            if ((m_MouseDown == MouseButtons.Left) && ((m_Selected >> 28) != 0xF) && (m_LastClicked == m_Selected))
            {
                float delta = -(e.Delta / 120f);
                delta = ((delta < 0f) ? -1f : 1f) * (float)Math.Pow(delta, 2f) * 0.05f;

                //m_SelectedObject.Position.X += delta * (float)Math.Cos(m_CamRotation.X) * (float)Math.Cos(m_CamRotation.Y);
               // m_SelectedObject.Position.Y += delta * (float)Math.Sin(m_CamRotation.Y);
               // m_SelectedObject.Position.Z += delta * (float)Math.Sin(m_CamRotation.X) * (float)Math.Cos(m_CamRotation.Y);

                float xdist = delta * (m_MouseCoords.X - (glLevelView.Width / 2f)) * m_PixelFactorX;
                float ydist = delta * (m_MouseCoords.Y - (glLevelView.Height / 2f)) * m_PixelFactorY;

                //m_SelectedObject.Position.X -= (xdist * (float)Math.Sin(m_CamRotation.X)) + (ydist * (float)Math.Sin(m_CamRotation.Y) * (float)Math.Cos(m_CamRotation.X));
                //m_SelectedObject.Position.Y += ydist * (float)Math.Cos(m_CamRotation.Y);
                //m_SelectedObject.Position.Z += (xdist * (float)Math.Cos(m_CamRotation.X)) - (ydist * (float)Math.Sin(m_CamRotation.Y) * (float)Math.Sin(m_CamRotation.X));

                //UpdateSelection();
            }
            else
            {
                float delta = -((e.Delta / 120.0f) * 0.5f);
                m_CamTarget.X += delta * (float)Math.Cos(m_CamRotation.X) * (float)Math.Cos(m_CamRotation.Y);
                m_CamTarget.Y += delta * (float)Math.Sin(m_CamRotation.Y);
                m_CamTarget.Z += delta * (float)Math.Sin(m_CamRotation.X) * (float)Math.Cos(m_CamRotation.Y);

                UpdateCamera();
            }

            glLevelView.Refresh();
        }

        private Vector3 Get3DCoords(Point coords2d, float depth)
        {
            Vector3 ret = m_CamPosition;

            ret.X -= (depth * (float)Math.Cos(m_CamRotation.X) * (float)Math.Cos(m_CamRotation.Y));
            ret.Y -= (depth * (float)Math.Sin(m_CamRotation.Y));
            ret.Z -= (depth * (float)Math.Sin(m_CamRotation.X) * (float)Math.Cos(m_CamRotation.Y));

            float x = (coords2d.X - (glLevelView.Width / 2f)) * m_PixelFactorX * depth;
            float y = -(coords2d.Y - (glLevelView.Height / 2f)) * m_PixelFactorY * depth;

            ret.X += (x * (float)Math.Sin(m_CamRotation.X)) - (y * (float)Math.Sin(m_CamRotation.Y) * (float)Math.Cos(m_CamRotation.X));
            ret.Y += y * (float)Math.Cos(m_CamRotation.Y);
            ret.Z -= (x * (float)Math.Cos(m_CamRotation.X)) + (y * (float)Math.Sin(m_CamRotation.Y) * (float)Math.Sin(m_CamRotation.X));

            return ret;
        }


    }
}
